package BVRServer;

import java.util.Vector;

import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;

import BVRClient.BVRC_Map;
import BVRClient.BVRC_Point;
import BVRClient.BVRC_Player.PLAYER_TEAM;
import BVRNetworking.BVRN_Definitions;
import BVRNetworking.BVRN_Packet;

public class BVRServerHandler extends IoHandlerAdapter
{
	private IoSession thisSession = null;
	
	public static ServerFrame serverFrame = null;
	public static Vector<BVRS_Player> players = null;
	
	public static BVRC_Map currentMap = new BVRC_Map();
	
	/**
	 * 
	 */
	static
	{
		players = new Vector<BVRS_Player>();
		
		currentMap.open("res/maps/test.map");
	}
	
	/**
	 * 
	 */
	BVRServerHandler()
	{
		
	}
	
	/**
	 * 
	 */
	public void exceptionCaught(IoSession session, Throwable t) throws Exception
	{
		appendLogText("Session Exception: " + t.toString());
	}
	
	/**
	 * 
	 */
	public void sessionCreated(IoSession session) throws Exception
	{
		this.thisSession = session;
	}
	
	/**
	 * 
	 */
	public void messageSent(IoSession session, Object msg) throws Exception
	{
		String message = msg.toString();
		
		if (message.length() <= 0)
			return;
		
		if (message.charAt(0) != BVRN_Definitions.BVRN_PLAYER_ROTATION)
		{
			appendLogText("Message sent: " + message);
		}
		
		System.out.println("Message sent: " + message);
	}
	
	/**
	 * 
	 */
	public void messageReceived(IoSession session, Object msg) throws Exception
	{
		String message = msg.toString();
		
		boolean showMessageRecieved = true;
		
		if (message.length() <= 0)
			return;
		
		BVRN_Packet packet = new BVRN_Packet(message);
		
		switch (packet.getType())
		{
			case BVRN_Definitions.BVRN_HEADER_CONNECT:
			{
				appendLogText("Client sent connect header.");
				
				BVRS_Player player = new BVRS_Player();
				player.setSession(session);
				player.setName("Guest");
				
				addPlayer(player);
				
				BVRS_PacketGenerator.createLocalPlayer(player).send(session);
				
				for (int i = 0; i < players.size(); i++)
				{
					BVRS_PacketGenerator.addPlayer(players.get(i)).send(session);
				}
				
				for (int i = 0; i < players.size(); i++)
				{
					BVRS_PacketGenerator.addPlayer(player).send(players.get(i).getSession());
				}
				
				BVRS_PacketGenerator.setMovementSpeed(BVRS_Settings.movementSpeed).send(session);
			}
			break;
			
			case BVRN_Definitions.BVRN_PLAYER_NAMESET:
			{
				appendLogText("Name change requested.");
				
				BVRS_Player player = getPlayerFromSession(session);
				
				if (player != null)
				{
					String oldName = player.getName();
					
					player.setName(packet.getParameter(0));
					
					appendLogText("Player name changed from " + oldName + " to " + player.getName());
				}
			}
			break;
			
			case BVRN_Definitions.BVRN_LOGIN:
			{
				/* TODO: Remove this completely
				appendLogText("Login requested");
				
				if (player != null)
				{
					player.setName(packet.getParameter(0));
					
					BVRS_PacketGenerator.createLocalPlayer(player).send(session);
				}
				
				for (int i = 0; i < players.size(); i++)
				{
					BVRS_PacketGenerator.addPlayer(players.get(i)).send(session);
				}
				
				for (int i = 0; i < players.size(); i++)
				{
					BVRS_PacketGenerator.addPlayer(player).send(players.get(i).getSession());
				}
				*/
			}
			break;
			
			case BVRN_Definitions.BVRN_PLAYER_ROTATION:
			{
				showMessageRecieved = false;
				
				BVRS_Player player = getPlayerFromSession(session);
				
				if (player != null)
				{
					player.setRotation(packet.getParameterFloat(0));
					
					for (int i = 0; i < players.size(); i++)
					{
						BVRS_PacketGenerator.playerRotation(player).send(players.get(i).getSession());
					}
				}
			}
			break;
			
			case BVRN_Definitions.BVRN_SET_PLAYER_POSITION:
			{
				BVRS_Player player = getPlayerFromSession(session);
				
				if (player != null)
				{
					player.setPosition(new BVRC_Point(packet.getParameterFloat(0), packet.getParameterFloat(1)));
					
					for (int i = 0; i < players.size(); i++)
					{
						BVRS_PacketGenerator.playerPosition(player).send(players.get(i).getSession());
					}
				}
			}
			break;
			
			case BVRN_Definitions.BVRN_SET_PLAYER_VELOCITY:
			{
				BVRS_Player player = getPlayerFromSession(session);
				
				if (player != null)
				{
					player.setMovementSpeedX(packet.getParameterInt(0));
					player.setMovementSpeedY(packet.getParameterInt(1));
					
					for (int i = 0; i < players.size(); i++)
					{
						BVRS_PacketGenerator.playerVelocity(player).send(players.get(i).getSession());
					}
				}
			}
			break;
			
			case BVRN_Definitions.BVRN_CREATE_PROJECTILE:
			{
				BVRS_Player player = getPlayerFromSession(session);
				
				for (int i = 0; i < players.size(); i++)
				{
					if (players.get(i) != player)
						packet.send(players.get(i).getSession());
				}
			}
			break;
			
			case BVRN_Definitions.BVRN_PLAYER_DEATH:
			{
				BVRS_Player player = getPlayerFromSession(session);
				
				if (player != null)
				{
					player.setPosition(currentMap.getBlueStartPosition());
					
					if (player.getTeam() == PLAYER_TEAM.RED)
					{
						player.setPosition(currentMap.getRedStartPosition());
					}
					
					for (int i = 0; i < players.size(); i++)
					{
						BVRS_PacketGenerator.playerPosition(player).send(players.get(i).getSession());
					}
				}
			}
			break;
			
			default:
				appendLogText("Unrecognised packet: " + message);
		}
		
		if (showMessageRecieved)
			appendLogText("Message recieved: " + message);
	}
	
	/**
	 * 
	 */
	public void sessionClosed(IoSession session) throws Exception
	{
		deletePlayer(getPlayerFromSession(session));
	}
	
	/**
	 * 
	 * @param name
	 * @return true if the name is not already in use on this server, false otherwise
	 */
	@SuppressWarnings("unused")
	private boolean isValidName(String name)
	{
		for (int i = 0; i < players.size(); i++)
		{
			//synchronized(players)
			{
				if (players.get(i).getName() == name)
					return false;
			}
		}
		
		return true;
	}
	
	private void appendLogText(String s)
	{
		if (serverFrame != null)
		{
			String entry = "";
			
			if (this.thisSession != null)
				entry += "(" + thisSession.getLocalAddress() + ")";
			
			entry += s;
				
			//synchronized(serverFrame)
			{
				serverFrame.appendLogText(entry);
			}
		}
	}
	
	/**
	 * 
	 * @param name
	 * @return true if the player was added, false in all other cases (most likely the name already exists)
	 */
	private boolean addPlayer(BVRS_Player player)
	{
		if (player == null)
			return false;
		
		//synchronized(players)
		{
			players.add(player);
		}
		
		this.setStartingInfo(player);
		
		appendLogText("Player added: " + player.getName());
		
		return true;
	}
	
	private void setStartingInfo(BVRS_Player player)
	{
		player.setPlayerID(this.generatePlayerID());
		player.setPosition(currentMap.getBlueStartPosition());
		player.setTeam(PLAYER_TEAM.BLUE);
		
		if (getNumPlayersOnTeam(PLAYER_TEAM.RED) < getNumPlayersOnTeam(PLAYER_TEAM.BLUE))
		{
			player.setPosition(currentMap.getRedStartPosition());
			player.setTeam(PLAYER_TEAM.RED);
		}
	}
	
	private int getNumPlayersOnTeam(PLAYER_TEAM team)
	{
		int ret = 0;
		
		for (int i = 0; i < players.size(); i++)
		{
			//synchronized(players)
			{
				if (players.get(i).getTeam() == team)
					ret++;
			}
		}
		
		return ret;
	}
	
	/**
	 * 
	 * @param name
	 * @return true if the player was deleted, false in all other cases
	 */
	private boolean deletePlayer(BVRS_Player player)
	{
		if (player == null)
			return false;
		
		boolean removed = false;
		
		//synchronized(players)
		{
			if (players.remove(player))
				removed = true;
		}
		
		if (removed)
			appendLogText("Player removed: " + player.getName());
		else
			appendLogText("Player cannot be removed: " + player.getName());
		
		appendLogText("Players in list: " + players.size());
		
		return removed;
	}
	
	/**
	 * 
	 * @param id
	 * @return the player id's vector index, -1 if the player is not found
	 */
	@SuppressWarnings("unused")
	private int getIndexAtID(int id)
	{
		for (int i = 0; i < players.size(); i++)
		{
			//synchronized (players)
			{
				if (players.get(i).getPlayerID() == id)
					return i;
			}
		}
		
		return -1;
	}
	
	/**
	 * 
	 * @param id
	 * @return the player id, null if no player is found
	 */
	public BVRS_Player getPlayerFromID(int id)
	{
		for (int i = 0; i < players.size(); i++)
		{
			if (players.get(i).getPlayerID() == id)
				return players.get(i);
		}
		
		return null;
	}
	
	/**
	 * 
	 * @param session
	 * @return the player using the given session, null if no player is found
	 */
	public BVRS_Player getPlayerFromSession(IoSession session)
	{
		for (int i = 0; i < players.size(); i++)
		{
			if (players.get(i).getSession() == session)
				return players.get(i);
		}
		
		return null;
	}
	
	/**
	 * 
	 * @return the next free player ID
	 */
	private int generatePlayerID()
	{
		int ret = 0;
		
		for (int i = 0; i < players.size(); i++)
		{
			//synchronized(players)
			{
				if (ret == players.get(i).getPlayerID())
				{
					ret++;
				}
			}
		}
		
		return ret;
	}
}
